﻿////需要记住websocketpp命名空间
//namespace websocketpp {
//	typedef lib::weak_ptr<void> connection_hdl;
//	template <typename config>
//	class endpoint : public config::socket_type {
//		typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;
//		typedef typename connection_type::ptr connection_ptr;
//		typedef typename connection_type::message_ptr message_ptr;
//		typedef lib::function<void(connection_hdl)> open_handler;
//		typedef lib::function<void(connection_hdl)> close_handler;
//		typedef lib::function<void(connection_hdl)> http_handler;
//		typedef lib::function<void(connection_hdl, message_ptr)>
//			message_handler;
//		/* websocketpp::log::alevel::none 禁⽌打印所有⽇志*/
//
//		void set_access_channels(log::level channels);/*设置⽇志打印等级*/
//		/*，在程序运行的时候，什么样的调试信息需要被打印出来，
//		什么不该打印出来，就是通过设置日志等级来控制*/
//		void clear_access_channels(log::level channels);/*清除指定等级的⽇志*/
//		/*设置指定事件的回调函数*/
//		/*回调函数相关接口:针对不同事件设置不同的处理函数，
//		websocketpp搭建了服务器之后，给不同的事件设置了不同的处理函数指针这些指针，
//		可以指向指定的函数，当服务器收到了指定的数据，
//		触发了指定的事件后就会通过函数指针去调用这些函数这时候，
//		我们程序员就可以编写一些业务处理函数，将其设置为对应事件的业务处理函数*/
//		void set_open_handler(open_handler h);/*websocket握⼿成功回调处理函数*/
//		void set_close_handler(close_handler h);/*websocket连接关闭回调处理函数*/
//		void set_message_handler(message_handler h);/*websocket消息回调处理函数*/
//		void set_http_handler(http_handler h);/*http请求回调处理函数*/
//		/*发送数据接⼝*/
//		void send(connection_hdl hdl, std::string& payload,
//			frame::opcode::value op);
//		void send(connection_hdl hdl, void* payload, size_t len,
//			frame::opcode::value op);
//		/*关闭连接接⼝*/
//		void close(connection_hdl hdl, close::status::value code, std::string&
//			reason);
//		/*获取connection_hdl 对应连接的connection_ptr*/
//		connection_ptr get_con_from_hdl(connection_hdl hdl);
//		/*websocketpp基于asio框架实现，init_asio⽤于初始化asio框架中的io_service调度
//		器*/
//		void init_asio();
//		/*设置是否启⽤地址重⽤*/
//		void set_reuse_addr(bool value);
//		/*设置endpoint的绑定监听端⼝*/
//		void listen(uint16_t port);
//		/*对io_service对象的run接⼝封装，⽤于启动服务器*/
//		std::size_t run();
//		/*websocketpp提供的定时器，以毫秒为单位*/
//		timer_ptr set_timer(long duration, timer_handler callback);
//	};
//
//	template <typename config>
//	class server : public endpoint<connection<config>, config> {
//		/*初始化并启动服务端监听连接的accept事件处理*/
//		void start_accept();
//	}；
//		template <typename config>
//	class connection
//		: public config::transport_type::transport_con_type
//		, public config::connection_base
//	{
//		/*发送数据接⼝*/
//		error_code send(std::string& payload, frame::opcode::value
//			op = frame::opcode::text);
//		/*获取http请求头部*/
//		std::string const& get_request_header(std::string const& key)
//			/*获取请求正⽂*/
//			std::string const& get_request_body();
//		/*设置响应状态码*/
//		void set_status(http::status_code::value code);
//		/*设置http响应正⽂*/
//		void set_body(std::string const& value);
//		/*添加http响应头部字段*/
//		void append_header(std::string const& key, std::string const& val);
//		/*获取http请求对象*/
//		request_type const& get_request();
//		/*获取connection_ptr 对应的 connection_hdl */
//		connection_hdl get_handle();
//	};
//	namespace http {
//		namespace parser {
//			class parser {
//				std::string const& get_header(std::string const& key)
//			}
//			class request : public parser {
//				/*获取请求⽅法*/
//				std::string const& get_method()
//					/*获取请求uri接⼝*/
//					std::string const& get_uri()
//			};
//		}
//	};
//	namespace message_buffer {
//		/*获取websocket请求中的payload数据类型*/
//		frame::opcode::value get_opcode();
//		/*获取websocket中payload数据*/
//		std::string const& get_payload();
//	};
//	namespace log {
//		struct alevel {
//			static level const none = 0x0;//日志等级
//			static level const connect = 0x1;
//			static level const disconnect = 0x2;
//			static level const control = 0x4;
//			static level const frame_header = 0x8;
//			static level const frame_payload = 0x10;
//			static level const message_header = 0x20;
//			static level const message_payload = 0x40;
//			static level const endpoint = 0x80;
//			static level const debug_handshake = 0x100;
//			static level const debug_close = 0x200;
//			static level const devel = 0x400;
//			static level const app = 0x800;
//			static level const http = 0x1000;
//			static level const fail = 0x2000;
//			static level const access_core = 0x00003003;
//			static level const all = 0xffffffff;
//		};
//	}
//	namespace http {
//		namespace status_code {
//			enum value {
//				uninitialized = 0,
//				continue_code = 100,
//				switching_protocols = 101,
//				ok = 200,
//				created = 201,
//				accepted = 202,
//				non_authoritative_information = 203,
//				no_content = 204,
//				reset_content = 205,
//				partial_content = 206,
//				multiple_choices = 300,
//				moved_permanently = 301,
//				found = 302,
//				see_other = 303,
//				not_modified = 304,
//				use_proxy = 305,
//				temporary_redirect = 307,
//				bad_request = 400,
//				unauthorized = 401,
//				payment_required = 402,
//				forbidden = 403,
//				not_found = 404,
//				method_not_allowed = 405,
//				not_acceptable = 406,
//				proxy_authentication_required = 407,
//				request_timeout = 408,
//				conflict = 409,
//				gone = 410,
//				length_required = 411,
//				precondition_failed = 412,
//				request_entity_too_large = 413,
//				request_uri_too_long = 414,
//				unsupported_media_type = 415,
//				request_range_not_satisfiable = 416,
//				expectation_failed = 417,
//				im_a_teapot = 418,
//				upgrade_required = 426,
//				precondition_required = 428,
//				too_many_requests = 429,
//				request_header_fields_too_large = 431,
//				internal_server_error = 500,
//				not_implemented = 501,
//				bad_gateway = 502,
//				service_unavailable = 503,
//				gateway_timeout = 504,
//				http_version_not_supported = 505,
//				not_extended = 510,
//				network_authentication_required = 511
//			};
//		}
//	}
//	namespace frame {
//		namespace opcode {
//			enum value {
//				continuation = 0x0,
//				text = 0x1,//文本形式
//				binary = 0x2,//二进制向欧美还是
//				rsv3 = 0x3,
//				rsv4 = 0x4,
//				rsv5 = 0x5,
//				rsv6 = 0x6,
//				rsv7 = 0x7,
//				close = 0x8,
//				ping = 0x9,
//				pong = 0xA,
//				control_rsvb = 0xB,
//				control_rsvc = 0xC,
//				control_rsvd = 0xD,
//				control_rsve = 0xE,
//				control_rsvf = 0xF,
//			};
//		}
//	}
//}


#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
using namespace std;
typedef websocketpp::server<websocketpp::config::asio> websocketsvr;
typedef websocketsvr::message_ptr message_ptr;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// websocket连接成功的回调函数
void OnOpen(websocketsvr* server, websocketpp::connection_hdl hdl) {
	cout << "连接成功" << endl;
}
// websocket连接成功的回调函数
void OnClose(websocketsvr* server, websocketpp::connection_hdl hdl) {
	cout << "连接关闭" << endl;
}
// websocket连接收到消息的回调函数
void OnMessage(websocketsvr* server, websocketpp::connection_hdl hdl, message_ptr
	cout << "收到消息" << msg->get_payload() << endl;
// 收到消息将相同的消息发回给websocket客⼾端
server->send(hdl, msg->get_payload(), websocketpp::frame::opcode::text);
}
// websocket连接异常的回调函数
void OnFail(websocketsvr* server, websocketpp::connection_hdl hdl) {
	cout << "连接异常" << endl;
}
// 处理http请求的回调函数 返回⼀个html欢迎⻚⾯
void OnHttp(websocketsvr* server, websocketpp::connection_hdl hdl) {
	cout << "处理http请求" << endl;
	websocketsvr::connection_ptr con = server->get_con_from_hdl(hdl);
	std::stringstream ss;
	ss << "<!doctype html><html><head>"
		<< "<title>hello websocket</title><body>"
		<< "<h1>hello websocketpp</h1>"
		<< "</body></head></html>";
	con->set_body(ss.str());
	con->set_status(websocketpp::http::status_code::ok);
}
int main() {
	// 使⽤websocketpp库创建服务器
	websocketsvr server;
	// 设置websocketpp库的⽇志级别
	// all表⽰打印全部级别⽇志
	// none表⽰什么⽇志都不打印
	server.set_access_channels(websocketpp::log::alevel::none);
	/*初始化asio*/
	server.init_asio();
	// 注册http请求的处理函数
	server.set_http_handler(bind(&OnHttp, &server, ::_1));
	// 注册websocket请求的处理函数
	server.set_open_handler(bind(&OnOpen, &server, ::_1));
	server.set_close_handler(bind(&OnClose, &server, _1));
	server.set_message_handler(bind(&OnMessage, &server, _1, _2));
	// 监听8888端⼝
	server.listen(8888);
	// 开始接收tcp连接
	server.start_accept();
	// 开始运⾏服务器
	server.run();
	return 0;
}
